package edu.sbcc.cs123;

import android.app.*;
import android.content.*;
import android.content.SharedPreferences.Editor;
import android.os.*;
import android.preference.*;
import android.view.*;
import android.widget.*;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.RadioGroup.OnCheckedChangeListener;

/**
 * TipCalculatorActivity is the main UI for the tip calculator app.
 * 
 * @author sstrenn
 * 
 */
public class TipCalculatorActivity extends Activity implements OnItemSelectedListener, OnCheckedChangeListener {

	private RelativeLayout mainLayout; // Base layout
	private Spinner numPayersView; // Lets user choose how many payers to compute for.
	private Spinner tipPercentView; // Allows user to select the tip percent.
	private EditText billView; // User's bill
	private EditText totalPerPayerView; // Amount that each payer must pay.
	private EditText tipPerPayerView; // Amount each payer will be tipping.
	private TextView tipTotalView; // Total amount of tip that will be paid to server.
	private TextView totalView; // Total amount that will be paid to the restaurant.
	private RadioGroup roundingGroup;
	private double taxRate = 0.0; // This is the local tax rate, dummy.
	private TextView tipPerPayerLabel;
	private TextView totalPerPayerLabel;
	private String rawBill = ""; // User-entered bill. ATM style, so this might be 12345, which would be displayed as
									// $123.45.

	private int[] backgroundIds = new int[] { R.drawable.black_background, R.drawable.blackmetal_background,
			R.drawable.black_fabric, R.drawable.blue_background, R.drawable.cyan_background,
			R.drawable.gray_background, R.drawable.graymetal_background, R.drawable.green_background,
			R.drawable.lime_background, R.drawable.orange_background, R.drawable.pink_background,
			R.drawable.red_background, R.drawable.yellow_background };


	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		try {
			super.onCreate(savedInstanceState);

			Display display = getWindowManager().getDefaultDisplay();
			if (display.getHeight() <= 480) {
				requestWindowFeature(Window.FEATURE_NO_TITLE);
				this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
						WindowManager.LayoutParams.FLAG_FULLSCREEN);
			}

			PreferenceManager.setDefaultValues(this, R.xml.preferences, false);

			// Build the UI.
			setContentView(R.layout.main);

			mainLayout = (RelativeLayout) findViewById(R.id.mainLayout);

			// Setup bill text
			billView = (EditText) findViewById(R.id.billView);

			// Set up num payers
			numPayersView = (Spinner) findViewById(R.id.numPayersView);
			ArrayAdapter<CharSequence> numPeopleAdapter = ArrayAdapter.createFromResource(this,
					R.array.number_of_payers, android.R.layout.simple_spinner_item);
			numPeopleAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
			numPayersView.setAdapter(numPeopleAdapter);
			numPayersView.setOnItemSelectedListener(this);

			// Set up tip percents
			tipPercentView = (Spinner) findViewById(R.id.tipPercentView);
			ArrayAdapter<CharSequence> tipPercentAdapter = ArrayAdapter.createFromResource(this, R.array.percents,
					android.R.layout.simple_spinner_item);
			tipPercentAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
			tipPercentView.setAdapter(tipPercentAdapter);
			tipPercentView.setOnItemSelectedListener(this);

			// Set up rounding listener
			roundingGroup = (RadioGroup) findViewById(R.id.roundingGroup);
			roundingGroup.setOnCheckedChangeListener(this);

			// Set up tipping results
			tipPerPayerView = (EditText) findViewById(R.id.tipPerPayerView);
			totalPerPayerView = (EditText) findViewById(R.id.totalPerPayerView);
			tipTotalView = (TextView) findViewById(R.id.tipTotalView);
			totalView = (TextView) findViewById(R.id.totalView);
			tipPerPayerLabel = (TextView) findViewById(R.id.tipPerPayerLabel);
			totalPerPayerLabel = (TextView) findViewById(R.id.totalPerPayerLabel);

			updateBillView();

			updateTipView();
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}
	}


	/**
	 * Build the options menu.
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		boolean b = false;
		try {
			new MenuInflater(this).inflate(R.menu.optionsmenu, menu);
			b = super.onCreateOptionsMenu(menu);
		} catch (Throwable t) {
			Toast.makeText(this, t.toString(), Toast.LENGTH_SHORT).show();
		}
		return b;
	}


	/**
	 * Handle app resumes by updating the settings and UI.
	 */
	@Override
	protected void onResume() {
		try {
			super.onResume();
			updateFromPreferences();
			updateTipView();
		} catch (Throwable t) {
			Toast.makeText(this, t.toString(), Toast.LENGTH_SHORT).show();
		}
	}


	/**
	 * Start the edit preferences activity.
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		boolean b = false;
		try {
			switch (item.getItemId()) {
			case R.id.settings:
				startActivity(new Intent(this, EditPreferencesActivity.class));
				break;
			}
			b = super.onOptionsItemSelected(item);
		} catch (Throwable t) {
			Toast.makeText(this, t.toString(), Toast.LENGTH_SHORT).show();
		}
		return b;
	}


	/**
	 * Update instance variables and UI state from the app preference store.
	 */
	private void updateFromPreferences() {
		SharedPreferences prefs = getSharedPreferences("TipCalculator", 0);
		String s = prefs.getString("background_image", "2");
		int backgroundIndex = Integer.parseInt(s);
		mainLayout.setBackgroundResource(backgroundIds[backgroundIndex]);

		s = prefs.getString("tax_rate", "0.0");
		taxRate = 0.0;
		try {
			taxRate = Double.parseDouble(s);
		} catch (NumberFormatException e) {
		}

		s = prefs.getString("num_payers", "1 Payer");
		String[] numberOfPayers = getResources().getStringArray(R.array.number_of_payers);
		int position = getIndexOfItem(numberOfPayers, s);
		position = (position == -1 ? 1 : position);
		numPayersView.setSelection(position);

		s = prefs.getString("tip_percent", "15% Tip");
		position = getIndexOfItem(getResources().getStringArray(R.array.percents), s);
		position = (position == -1 ? 14 : position);
		tipPercentView.setSelection(position);

		int id = prefs.getInt("rounding_id", -1);
		if (id != -1) {
			try {
				RadioButton roundingRadioButton = (RadioButton) findViewById(id);
				roundingRadioButton.setChecked(true);
			} catch (Exception ex) {
			}
		}

	}


	/**
	 * Gets the index of item within data. Returns -1 if item is not found. Comparison is done via the .equals method.
	 * 
	 * @param data
	 * @param item
	 * @return
	 */
	public int getIndexOfItem(String[] data, String item) {
		int index = -1;

		for (int ndx = 0; ndx < data.length; ndx++) {
			if (data[ndx].equals(item)) {
				index = ndx;
				break;
			}
		}

		return index;
	}


	/**
	 * Display message as a toast of the given duration.
	 * 
	 * @param message
	 * @param duration
	 */
	public void showToast(String message, int duration) {
		Toast.makeText(this, message, duration).show();
	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onOneButtonClick(View view) {
		try {
			addDigit("1");
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}

	}


	private void addDigit(String digit) {
		if (rawBill.length() < 6) {
			rawBill += digit;
			new UpdateViewTask().execute();
		}
	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onTwoButtonClick(View view) {
		try {
			addDigit("2");
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}

	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onThreeButtonClick(View view) {
		try {
			addDigit("3");
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}

	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onFourButtonClick(View view) {
		try {
			addDigit("4");

		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}

	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onFiveButtonClick(View view) {
		try {
			addDigit("5");

		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}
	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onSixButtonClick(View view) {
		try {
			addDigit("6");

		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}
	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onSevenButtonClick(View view) {
		try {
			addDigit("7");

		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}
	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onEightButtonClick(View view) {
		try {
			addDigit("8");

		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}
	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onNineButtonClick(View view) {
		try {
			addDigit("9");
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}
	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onZeroButtonClick(View view) {
		try {
			if (rawBill.length() >= 1) {
				addDigit("0");
			}
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}

	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onBackspaceButtonClick(View view) {
		try {
			if (rawBill.length() > 0)
				rawBill = rawBill.substring(0, rawBill.length() - 1);
			new UpdateViewTask().execute();
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}

	}


	/**
	 * Handle the button by updating the raw bill text and then updating the view asynchronously.
	 * 
	 * @param view
	 */
	public void onClearButtonClick(View view) {
		try {
			rawBill = "";
			new UpdateViewTask().execute();
		} catch (Throwable t) {
			showToast(t.toString(), Toast.LENGTH_LONG);
		}
	}


	/**
	 * Update the bill based on the numbers the user has entered.
	 */
	public void updateBillView() {
		int length = rawBill.length();

		if (length == 0)
			billView.setText("$0.00");
		else if (length == 1)
			billView.setText("$0.0" + rawBill);
		else if (length == 2)
			billView.setText("$0." + rawBill);
		else
			billView.setText("$" + rawBill.substring(0, length - 2) + "." + rawBill.substring(length - 2));
	}


	/**
	 * Updates the tipping information based on the user-entered bill, # of payers, tip %, and tax rate.
	 */
	public void updateTipView() {
		try {
			int numPayers = numPayersView.getSelectedItemPosition() + 1;

			// Set "per player" visibility
			if (numPayers > 1) {
				tipPerPayerLabel.setVisibility(View.VISIBLE);
				totalPerPayerLabel.setVisibility(View.VISIBLE);
			} else {
				tipPerPayerLabel.setVisibility(View.INVISIBLE);
				totalPerPayerLabel.setVisibility(View.INVISIBLE);
			}

			if (rawBill.equals("")) {
				tipPerPayerView.setText("");
				totalPerPayerView.setText("");
				tipTotalView.setText("");
				totalView.setText("");
			} else {
				double bill = Double.parseDouble(billView.getText().toString().substring(1).toString());
				String selectedTipPercent = tipPercentView.getSelectedItem().toString();
				double tipPercent = Double
						.parseDouble(selectedTipPercent.substring(0, selectedTipPercent.length() - 5));

				double tip = (bill / (1 + taxRate / 100.0)) * tipPercent / 100.0;
				double total = bill + tip;
				double tipPerPayer = tip / numPayers;
				double totalPerPayer = total / numPayers;

				switch (roundingGroup.getCheckedRadioButtonId()) {
				case R.id.roundTipView:
					int t = (int) Math.ceil(tip);
					while (t % numPayers != 0)
						t++;
					tip = t;
					tipPerPayer = tip / numPayers;
					total = bill + tip;
					totalPerPayer = total / numPayers;
					break;

				case R.id.roundTotalView:
					t = (int) Math.ceil(total);
					while (t % numPayers != 0)
						t++;
					total = t;
					totalPerPayer = total / numPayers;
					tip = total - bill;
					tipPerPayer = tip / numPayers;
					break;
				}

				if (numPayers > 1) {
					tipTotalView.setText("$" + String.format("%1$.2f", tip));
					totalView.setText("$" + String.format("%1$.2f", total));
					tipPerPayerView.setText("$" + String.format("%1$.2f", tipPerPayer));
					totalPerPayerView.setText("$" + String.format("%1$.2f", totalPerPayer));
				} else {
					tipPerPayerView.setText("");
					totalPerPayerView.setText("");
					tipTotalView.setText("$" + String.format("%1$.2f", tipPerPayer));
					totalView.setText("$" + String.format("%1$.2f", totalPerPayer));
				}

			}
		} catch (Throwable t) {
			rawBill = "";
			updateTipView();
		}
	}


	/**
	 * Handle app pause by saving the preferences.
	 */
	@Override
	protected void onPause() {
		try {
			super.onPause();
			updatePreferences();
		} catch (Throwable t) {
			Toast.makeText(this, t.toString(), Toast.LENGTH_SHORT).show();
		}
	}


	/**
	 * Update the preferences that aren't already handled in via EditPreferencesActivity.
	 */
	private void updatePreferences() {
		SharedPreferences prefs = getSharedPreferences("TipCalculator", 0);
		Editor editor = prefs.edit();
		editor.putString("num_payers", numPayersView.getSelectedItem().toString());
		editor.putString("tip_percent", tipPercentView.getSelectedItem().toString());
		editor.putInt("rounding_id", roundingGroup.getCheckedRadioButtonId());
		editor.commit();
	}


	/**
	 * Handles item selection by updating the tipping information.
	 */
	@Override
	public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
		try {
			updateTipView();
		} catch (Throwable t) {
			Toast.makeText(this, t.toString(), Toast.LENGTH_SHORT).show();
		}
	}


	@Override
	public void onNothingSelected(AdapterView<?> arg0) {
		// TODO Auto-generated method stub

	}


	/**
	 * Handles the rounding method change by updating the tipping information.
	 */
	@Override
	public void onCheckedChanged(RadioGroup group, int checkedId) {
		try {
			updateTipView();
		} catch (Throwable t) {
			Toast.makeText(this, t.toString(), Toast.LENGTH_SHORT).show();
		}
	}

	/**
	 * AsyncTask that updates the bill view synchronously, then updates the tipping view asynchronously.
	 * 
	 * @author sstrenn
	 * 
	 */
	private class UpdateViewTask extends AsyncTask<Void, Integer, Exception> {

		@Override
		protected void onPreExecute() {
			try {
				super.onPreExecute();

				updateBillView();

			} catch (Throwable t) {
				showToast(t.toString(), Toast.LENGTH_LONG);
			}

		}


		@Override
		protected Exception doInBackground(Void... params) {

			return null;
		}


		@Override
		protected void onPostExecute(Exception error) {
			try {
				super.onPostExecute(error);
				updateTipView();
			} catch (Exception ex) {
				showToast(ex.getMessage(), Toast.LENGTH_LONG);
			}
		}
	}

}